package com.ruyuan.little.project.elasticsearch.biz.admin.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruyuan.little.project.common.dto.CommonResponse;
import com.ruyuan.little.project.common.dto.TableData;
import com.ruyuan.little.project.elasticsearch.biz.admin.dto.AdminGoodsStoreDTO;
import com.ruyuan.little.project.elasticsearch.biz.admin.entity.AdminGoodsStore;
import com.ruyuan.little.project.elasticsearch.biz.admin.mapper.AdminGoodsStoreMapper;
import com.ruyuan.little.project.elasticsearch.biz.admin.service.AdminGoodsStoreService;
import com.ruyuan.little.project.elasticsearch.biz.common.constant.QueryFiledNameConstant;
import com.ruyuan.little.project.elasticsearch.biz.common.constant.StringPoolConstant;
import com.ruyuan.little.project.elasticsearch.biz.common.dao.ElasticsearchDao;
import com.ruyuan.little.project.elasticsearch.biz.common.dto.GoodsRelationField;
import com.ruyuan.little.project.elasticsearch.biz.common.utils.ElasticClientUtil;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.UUIDs;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author dulante
 * version: 1.0
 * Description:后台商品店铺service组件实现类
 **/
@Service
public class AdminGoodsStoreServiceImpl implements AdminGoodsStoreService {

    /**
     * 日志组件
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(AdminGoodsStoreServiceImpl.class);

    @Autowired
    private AdminGoodsStoreMapper adminGoodsStoreMapper;

    /**
     * es rest client api
     */
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * elasticsearch Dao 组件
     */
    @Autowired
    private ElasticsearchDao elasticsearchDao;

    /**
     * 店铺index别名
     */
    @Value("${elasticsearch.storeIndexAlias}")
    private String storeIndexAlias;

    /**
     * 店铺index名称
     */
    @Value("${elasticsearch.storeIndex}")
    private String storeIndex;

    /**
     * 店铺商品index别名
     */
    @Value("${elasticsearch.goodsIndexAlias}")
    private String goodsIndexAlias;


    /**
     * 店铺的mapping
     */
    @Value(value = "classpath:/mapping/storeIndex.json")
    private Resource storeIndexMappingResource;

    /**
     * 初始化店铺的索引
     *
     * @throws IOException
     */
    @PostConstruct
    public void init() throws IOException {
        // 查询店铺索引是否存在
        boolean storeIndexExistFlag = elasticsearchDao.indexExistFlag(storeIndex);
        if (!storeIndexExistFlag) {
            // 不存在
            // 创建店铺索引
            Boolean created = elasticsearchDao.createIndex(storeIndex, storeIndexAlias, storeIndexMappingResource);
            LOGGER.info("create index {} ", created ? "success" : "fail");
        } else {
            LOGGER.info("index:{} already exist", storeIndex);
        }
    }

    @Override
    public CommonResponse<TableData<AdminGoodsStore>> getStorePageByStoreNameFromDB(AdminGoodsStoreDTO adminGoodsStoreDTO) {
        Integer page = adminGoodsStoreDTO.getPage();
        LOGGER.info("开始调用GoodsStoreServiceImpl类getStorePageByStoreNameFromDB方法, 方法使用参数:[[storePageDTO]:{}]", JSON.toJSONString(adminGoodsStoreDTO));
        // page给默认的值
        if (Objects.isNull(page) || page == 0) {
            page = 1;
        }

        TableData<AdminGoodsStore> tableData = new TableData<>();

        String storeName = adminGoodsStoreDTO.getStoreName();
        long count = adminGoodsStoreMapper.countStorePageByStoreName(storeName);
        tableData.setTotal(count);
        if (count > 0) {
            Integer size = adminGoodsStoreDTO.getSize();
            List<AdminGoodsStore> goodsStoreList = adminGoodsStoreMapper.getStorePageByStoreName(storeName, (page - 1) * size, size);
            tableData.setRows(goodsStoreList);
        }
        LOGGER.info("结束调用GoodsStoreServiceImpl类getStorePageByStoreNameFromDB方法,结果:{}", JSON.toJSONString(tableData));
        return CommonResponse.success(tableData);
    }

    @Override
    public CommonResponse<TableData<AdminGoodsStore>> getStorePageByStoreNameFromEs(AdminGoodsStoreDTO adminGoodsStoreDTO) {
        LOGGER.info("开始调用GoodsStoreServiceImpl类getStorePageByStoreNameFromEs方法, 方法使用参数:[[storePageDTO]:{}]", JSON.toJSONString(adminGoodsStoreDTO));

        // 请求参数
        String storeName = adminGoodsStoreDTO.getStoreName();
        Integer page = adminGoodsStoreDTO.getPage();
        Integer size = adminGoodsStoreDTO.getSize();

//        使用父子关系模型前,查询storeIndexAlias
//        // 构建店铺分页查询请求体
//        SearchSourceBuilder sourceBuilder = this.buildStorePageQueryBuilder(storeName, page, size);
//
//        // 查询请求
//        SearchRequest searchRequest = new SearchRequest(storeIndexAlias);

        // 使用父子关系模型之后,查询goodsIndexAlias
        // 构建店铺分页查询请求体
        SearchSourceBuilder sourceBuilder = this.buildStorePageQueryBuilderFromParentAndChildIndex(storeName, page, size);

        // 查询请求
        SearchRequest searchRequest = new SearchRequest(goodsIndexAlias);

        searchRequest.source(sourceBuilder);

        try {
            LOGGER.info("从es查询店铺请求参数：{}", searchRequest.source().toString());
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            // 构建查询结果
            TableData<AdminGoodsStore> tableData = this.buildStorePageResult(searchResponse);
            LOGGER.info("结束调用GoodsStoreServiceImpl类getStorePageByStoreNameFromEs方法,结果:{}", JSON.toJSONString(tableData));
            return CommonResponse.success(tableData);
        } catch (IOException e) {
            LOGGER.error("从es查询店铺列表失败", e);
        }
        return CommonResponse.fail();
    }

    /**
     * 构建店铺分页结果
     *
     * @param searchResponse es查询响应结果
     * @return 店铺列表
     */
    private TableData<AdminGoodsStore> buildStorePageResult(SearchResponse searchResponse) {
        TableData<AdminGoodsStore> tableData = new TableData<>();
        SearchHits hits = searchResponse.getHits();
        long total = hits.getTotalHits().value;
        tableData.setTotal(total);

        // 店铺列表
        List<AdminGoodsStore> goodsStores = new ArrayList<>();
        if (total > 0) {
            // 封装数据
            for (SearchHit hit : hits) {
                AdminGoodsStore goodsStore = JSON.parseObject(hit.getSourceAsString(), AdminGoodsStore.class);
                goodsStores.add(goodsStore);
            }
        }
        tableData.setRows(goodsStores);
        return tableData;
    }

    /**
     * 构建分页查询店铺信息的请求体
     *
     * @param storeName 查询的店铺名称
     * @param page      页码
     * @param size      每页大小
     * @return 查询资源构建器
     */
    private SearchSourceBuilder buildStorePageQueryBuilder(String storeName, Integer page, Integer size) {
        // 获取分页查询构造器
        SearchSourceBuilder sourceBuilder = ElasticClientUtil.builderPageSearchBuilder(page, size);

        // 查询字段不为空，则添加店铺名称查询
        if (!ObjectUtils.isEmpty(storeName)) {
            sourceBuilder.query(QueryBuilders.wildcardQuery(
                    QueryFiledNameConstant.STORE_NAME + StringPoolConstant.DOT + QueryFiledNameConstant.KEYWORD,
                    StringPoolConstant.STAR + storeName + StringPoolConstant.STAR));
        }
        return sourceBuilder;
    }

    /**
     * 构建分页查询店铺信息的请求体
     *
     * @param storeName 查询的店铺名称
     * @param page      页码
     * @param size      每页大小
     * @return 查询资源构建器
     */
    private SearchSourceBuilder buildStorePageQueryBuilderFromParentAndChildIndex(String storeName, Integer page,
                                                                          Integer size) {

        // 获取分页查询构造器
        SearchSourceBuilder sourceBuilder = ElasticClientUtil.builderPageSearchBuilder(page, size);

        // 指定关联关系字段为店铺
        MatchQueryBuilder relationQueryBuilder = QueryBuilders.matchQuery(GoodsRelationField.RELATION_FIELD_NAME, GoodsRelationField.GOODS_STORE);
        // 构建查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery().must(relationQueryBuilder);


        // 查询字段不为空，则添加店铺名称查询
        if (!ObjectUtils.isEmpty(storeName)) {
            boolQuery.must(QueryBuilders.wildcardQuery(QueryFiledNameConstant.STORE_NAME,
                    StringPoolConstant.STAR + storeName + StringPoolConstant.STAR));
        }
        sourceBuilder.query(boolQuery);
        return sourceBuilder;
    }


    @Override
    public CommonResponse insertGoodsStore(AdminGoodsStore adminGoodsStore) {
        adminGoodsStore.setId(UUIDs.base64UUID());
        IndexRequest indexRequest = new IndexRequest(goodsIndexAlias);
        indexRequest.id(adminGoodsStore.getId());
        adminGoodsStore.setOpenDate(LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE));
        indexRequest.source(JSONObject.toJSONString(adminGoodsStore), XContentType.JSON);
        return elasticsearchDao.insert(indexRequest);
    }

    @Override
    public CommonResponse deleteStoreById(String id) {
        DeleteRequest deleteRequest = new DeleteRequest(goodsIndexAlias, id);
        return elasticsearchDao.delete(deleteRequest);
    }

}
